package com.example.searchenginebackend.once;

import com.example.searchenginebackend.components.IndexComponent;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 解析本地Java离线文档构建索引
 * @author 米饭好好吃
 */
@Component
@Slf4j
public class Parser {
    @Resource
    private IndexComponent indexComponent;

    public static final String DOC_ROOT_PATH = "D:\\code\\projects\\project\\JavaDocSearchEngine\\searchengine-backend\\java8_doc"; // 文件根路径
    public static final String DOC_NETWORK_URL_PREFIX = "https://docs.oracle.com/javase/8/"; // 网络固定前缀
    public static final String HTML_POSTFIX = ".html";

    /**
     * 枚举文件
     * @return 返回根目录下所有.html文件列表
     */
    public List<File> enumFiles() {
        // 1. 构建根路径对应文件
        File rootFile = new File(DOC_ROOT_PATH);
        // 2. 创建存放全部文件的列表
        List<File> fileList = new ArrayList<>();
        // 3. 判断根目录是否合法
        if (!rootFile.isDirectory()) {
            return fileList;
        }
        // 3. 递归整理根路径所有的.html文件存放到fileList中
        dfsSearchFiles(rootFile, fileList);
        return fileList;
    }

    /**
     * 递归搜集根目录下所有的.html文件
     * @param rootFile 根目录文件
     * @param fileList 目标存放列表
     */
    private void dfsSearchFiles(File rootFile, List<File> fileList) {
        // 1. 列举目录下搜有的文件
        File[] files = rootFile.listFiles();
        // 2. 逐个判断
        for (File file : files) {
            if (file.isDirectory()) {
                // 如果是目录继续递归
                dfsSearchFiles(file, fileList);
            } else {
                // 如果是普通文件就判断后缀
                if (file.getName().endsWith(".html")) {
                    fileList.add(file);
                }
            }
        }
    }

    @Scheduled(cron = "0 41 16 * * *") // 开启定时任务
    public void parse() {
        log.info("开始进行解析...");
        // 1. 创建Parser实例
        Parser parser = new Parser();
        // 2. 获取全部的.html文件
        List<File> fileList = parser.enumFiles();
        // 3. 枚举每一个文件进行解析
        for (File file : fileList) {
            // 3.1 获取title
            String title = parser.parseTitle(file);
            // 3.2 获取url
            String url = parser.parseUrl(file);
            // 3.3 获取content
            String content = parser.parseContent(file);
            // 3.4 添加索引
            indexComponent.addIndex(title, url, content);
        }
        // 3.5 保存索引
        indexComponent.save();
    }

    /**
     *
     * 解析文件获取文章内容
     * @param file 目标文件
     * @return 文件对应content
     */
    private String parseContent(File file) {
        String sourceContent = getSourceContent(file);
        // 1. 去除<script>标签及其内容
        sourceContent = sourceContent.replaceAll("<script(.*?)>(.*?)</script>", " ");
        StringBuilder stringBuilder = new StringBuilder();
        // 2. 开始循环读取
        boolean canRead = true;
        for (char ch : sourceContent.toCharArray()) {
            if (ch == '<') {
                // 不能读取
                canRead = false;
                continue;
            }
            if (ch == '>') {
                // 可以开始读取
                canRead = true;
                continue;
            }
            if (canRead) {
                stringBuilder.append(ch);
            }
        }
        // 3. 将多个空白字符合并为一个字符（借助正则表达式）
        String ret = stringBuilder.toString();
        ret = ret.replaceAll("\\s+", " ");
        return ret;
    }

    private String getSourceContent(File file) {
        try (FileReader fileReader = new FileReader(file)) {
            StringBuilder stringBuilder = new StringBuilder();
            // 循环读取字符
            int readRes = -1;
            // 读取策略：碰到<暂停读取，读到>可以读取（去除标签）
            while ((readRes = fileReader.read()) != -1) {
                char ch = (char) readRes;
                stringBuilder.append(ch);
            }
            return stringBuilder.toString();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     *
     * 解析文件获取跳转url
     * @param file 目标文件
     * @return 文件对应url
     */
    private String parseUrl(File file) {
        // 1. 从文件绝对路径中解析出和根目录相对目录
        String relativePath = file.getAbsolutePath().substring(DOC_ROOT_PATH.length() + 1);
        // 2. 拼接上固定网络前缀
        String netUrl = DOC_NETWORK_URL_PREFIX + relativePath;
        // 3. 将反斜杠替换为正斜杠
        netUrl = netUrl.replace("\\", "/");
        return netUrl;
    }

    /**
     * 解析文件获取标题
     * @param file 目标文件
     * @return 文件对应标题
     */
    private String parseTitle(File file) {
        String fileName = file.getName();
        return fileName.substring(0, fileName.length() - HTML_POSTFIX.length());
    }
}
